<template>
  <div class="hc-table">
    <el-table
      ref="tableRef"
      :data="tableData"
      v-bind="_options"
      header-row-class-name="header-row-class-name"
      @selection-change="handleSelectionChange"
      @row-click="handleRowClick"
      @cell-click="handleCellClick"
      @sort-change="handleSortChange"
    >
      <template v-for="(col, index) in columns">
        <!---复选框, 序号 (START)-->
        <el-table-column
          :key="index"
          v-if="
            col.type === 'index' ||
            col.type === 'selection' ||
            col.type === 'expand'
          "
          :sortable="col.sortable"
          :prop="col.prop"
          :align="col.align"
          :label="col.label"
          :type="col.type"
          :index="indexMethod"
          :width="col.width"
          v-bind="col"
        />

        <!---复选框, 序号 (END)-->
        <TableColumn
          :key="index + '_key'"
          :col="col"
          v-else
          @command="handleAction"
        >
          <template #default="{ slotName, row, index }">
            <slot :name="slotName" :row="row" :index="index" />
          </template>
          <!-- 自定义表头插槽 -->
          <template #customHeader="{ slotName, column, index }">
            <slot :name="slotName" :column="column" :index="index" />
          </template>
        </TableColumn>
      </template>
    </el-table>
  </div>
  <!-- 分页器 -->
  <div
    v-if="_options.showPagination"
    class="table-pagination"
    :class="[`pagination_${_options.paginationPosition}`]"
  >
    <el-pagination
      v-bind="_paginationConfig"
      @size-change="pageSizeChange"
      @current-change="currentPageChange"
    />
  </div>
</template>
<script setup>
import { computed, ref } from "vue";
import TableColumn from "./TableColumn.vue";
// import { ElTable } from 'element-plus'

// type VNodeChild = import('vue').VNodeChild
// type Type = 'selection' | 'index' | 'expand' | 'image' | 'date'
// type Size = 'large' | 'default' | 'small'
// type Align = 'center' | 'left' | 'right'
// type Command = string | number
// type DateFormat = 'YYYY-MM-DD' | 'YYYY-MM-DD HH:mm:ss' | 'YYYY-MM-DD HH:mm' | 'YYYY-MM'
// type Order = 'ascending' | 'descending'
// interface ButtonItem {
//   name: string,
//   command: Command,
//   size?: Size
//   type?: 'primary' | 'success' | 'warning' | 'danger' | 'info',
// }
// interface Sort {
//   prop: string
//   order: Order
//   init?: any
//   silent?: any
// }

const props = defineProps({
  tableData: {
    //  table的数据
    type: Array,
    default: () => {
      return [];
    },
  },
  columns: {
    //  每列的配置项
    // 对应列的类型。 如果设置了selection则显示多选框； 如果设置了 index 则显示该行的索引（从 1 开始计算）； 如果设置了 expand 则显示为一个可展开的按钮
    // type?: Type,
    // label?: string,
    // prop?: string,
    // slot?: string
    // width?: string,
    // align?: Align,
    // dateFormat?: DateFormat // 显示在页面中的日期格式，简单列举了几种格式， 可自行配置
    // showOverflowTooltip?: boolean,
    // buttons?: ButtonItem[],
    // render?: (row?: Record<string, any>, index?: number) => VNodeChild // 渲染函数，渲染这一列的每一行的单元格
    // sortable?: boolean | 'custom', // 对应列是否可以排序， 如果设置为 'custom'，则代表用户希望远程排序，需要监听 Table 的 sort-change 事件
    // headerRender?: ({ column, index }) => VNodeChild, // 渲染函数，渲染列表头
    // headerSlot?: string, // 自定义表头插槽名字
    // children?: Column[] // 配置多级表头的数据集合, 具体用法可参考多级表头使用示例。
    type: Array,
    default: () => {
      return [];
    },
  },
  options: {
    //  table的配置
    // height?: string | number,
    // // Table 的高度， 默认为自动高度。 如果 height 为 number 类型，单位 px；如果 height 为 string 类型，则这个高度会设置为 Table 的 style.height 的值，Table 的高度会受控于外部样式。
    // stripe?: boolean, // 是否为斑马纹 table
    // maxHeight?: string | number, // Table 的最大高度。 合法的值为数字或者单位为 px 的高度。
    // size?: Size // Table 的尺寸
    // showHeader?: boolean // 是否显示表头,
    // tooltipEffect?: 'dark' | 'light' // tooltip effect 属性
    // showPagination?: boolean, // 是否展示分页器
    // paginationPosition?: 'left' | 'center' | 'right', // 分页器位置
    // paginationConfig?: Pagination, // 分页器配置项，详情见下方 paginationConfig 属性,
    // rowStyle?: ({ row, rowIndex }) => stirng | object // 行的 style 的回调方法，也可以使用一个固定的 Object 为所有行设置一样的 Style。
    // defaultSort?: Sort // 默认的排序列的 prop 和顺序。 它的 prop 属性指定默认的排序的列，order 指定默认排序的顺序。
    // rowKey?: string // 行数据的 Key，用来优化 Table 的渲染。
    //
    // paginationConfig 属性:
    // total?: number, // 总条目数
    // currentPage: number, // 当前页数，支持 v-model 双向绑定
    // pageSize: number, // 每页显示条目个数，支持 v-model 双向绑定
    // pageSizes?: number[], // 每页显示个数选择器的选项设置
    // layout?: string, // 组件布局，子组件名用逗号分隔
    // background?: boolean // 是否为分页按钮添加背景色
    type: Object,
    default: () => {
      return {};
    },
  },
});
const tableRef = ref();
// 设置option默认值，如果传入自定义的配置则合并option配置项
const _options = computed(() => {
  const option = {
    stripe: false,
    tooltipEffect: "dark",
    showHeader: true,
    showPagination: false,
    paginationPosition: "right",
    rowStyle: () => "cursor:pointer", // 行样式
    // headerRowClassName: 'table-header-row',
  };
  return Object.assign(option, props?.options);
});
// 合并分页配置
const _paginationConfig = computed(() => {
  const config = {
    total: 0,
    currentPage: 1,
    pageSize: 10,
    pageSizes: [10, 20, 50],
    background: true,
    layout: "total, sizes, prev, pager, next, jumper",
  };
  return Object.assign(config, _options.value.paginationConfig);
});

const emit = defineEmits([
  "selection-change", // 当选择项发生变化时会触发该事件
  "row-click", // 当某一行被点击时会触发该事件
  "cell-click", // 当某个单元格被点击时会触发该事件
  "command", // 按钮组事件
  "size-change", // pageSize事件
  "current-change", // currentPage按钮组事件
  "pagination-change", // currentPage或者pageSize改变触发
  "sort-change", // 列排序发生改变触发
]);
// 自定义索引
const indexMethod = (index) => {
  const tabIndex =
    index +
    (_paginationConfig.value.currentPage - 1) *
      _paginationConfig.value.pageSize +
    1;
  return tabIndex;
};
// 切换pageSize
const pageSizeChange = (pageSize) => {
  emit("size-change", pageSize);
  emit("pagination-change", 1, pageSize);
};
// 切换currentPage
const currentPageChange = (currentPage) => {
  emit("current-change", currentPage);
  emit("pagination-change", currentPage, _paginationConfig.value.pageSize);
};
// 按钮组事件
const handleAction = (command, row) => {
  emit("command", command, row);
};
// 多选事件
const handleSelectionChange = (val) => {
  emit("selection-change", val);
};
// 当某一行被点击时会触发该事件
const handleRowClick = (row, column, event) => {
  emit("row-click", row, column, event);
};
// 当某个单元格被点击时会触发该事件
const handleCellClick = (row, column, cell, event) => {
  emit("cell-click", row, column, cell, event);
};
/**
 *  当表格的排序条件发生变化的时候会触发该事件
 * 在列中设置 sortable 属性即可实现以该列为基准的排序， 接受一个 Boolean，默认为 false。
 * 可以通过 Table 的 default-sort 属性设置默认的排序列和排序顺序。
 * 如果需要后端排序，需将 sortable 设置为 custom，同时在 Table 上监听 sort-change 事件，
 * 在事件回调中可以获取当前排序的字段名和排序顺序，从而向接口请求排序后的表格数据。
 */
const handleSortChange = ({ column, prop, order }) => {
  emit("sort-change", { column, prop, order });
};
// 暴露给父组件参数和方法，如果外部需要更多的参数或者方法，都可以从这里暴露出去。
defineExpose({ element: tableRef });
</script>
<style lang="scss" scoped>
:deep(.el-image__inner) {
  transition: all 0.3s;
  cursor: pointer;
  &:hover {
    transform: scale(1.2);
  }
}

.hc-table {
  flex: 1;
  position: relative;
  overflow: hidden;
  .el-table {
    height: 100%;
    position: absolute;
  }
}

.table-pagination {
  margin-top: 20px;
  display: flex;
  align-items: center;
}
.table-pagination.pagination_left {
  justify-content: flex-start;
}
.table-pagination.pagination_center {
  justify-content: center;
}
.table-pagination.pagination_right {
  justify-content: flex-end;
}
</style>
